
#include <level/slide/object/object.hpp>
#include <boost/algorithm/string.hpp>

object::~object( )
{
}

void object::step( float delta_time )
{
	if ( m_animation != nullptr )
	{
		m_animation->update( delta_time );

		if ( m_body != nullptr )
		{
			m_animation->move_to( g_scale_b2_position * m_body->GetPosition( ) );
			m_animation->rotate_to( b2RadToDeg( m_body->GetAngle( ) ) );
		}
	}
}

void object::draw( )
{
	if ( m_animation != nullptr )
	{
		sf::IntRect const & size = m_animation->size( );
		m_animation->draw( size.GetWidth( ) * -0.5f, size.GetHeight( ) * -0.5f );
	}
}

object::object( )
{
}

void object::add_shape( rapidxml::xml_node<> * shape_node )
{
	if ( rapidxml::xml_attribute<>* type_attribute = shape_node->first_attribute( "type" ) )
	{
		b2FixtureDef definition;
		definition.density = read_from_node<float32>( shape_node->first_node( "density" ), definition.density );
		definition.friction = read_from_node<float32>( shape_node->first_node( "friction" ), definition.friction );
		definition.restitution = read_from_node<float32>( shape_node->first_node( "restitution" ), definition.restitution );
		definition.isSensor = read_from_node<bool>( shape_node->first_node( "is_sensor" ), definition.isSensor );

		if ( rapidxml::xml_node<> * on_collide_messages_node = shape_node->first_node( "on_collide_messages" ) )
		{
			std::string const all_messages( on_collide_messages_node->value( ) );

			std::vector<std::string> individual_messages;
			boost::algorithm::split( individual_messages, all_messages, boost::algorithm::is_any_of( "\t \n" ) );

			std::for_each( individual_messages.cbegin( ), individual_messages.cend( ), [this]( std::string const & message )
			{
				if ( message != "" )
				{
					m_user_data->add_message( message );
				}
			} );
		}

		std::string const type = type_attribute->value( );
		if ( type == "polygon" )
		{
			if ( rapidxml::xml_node<>* vertices = shape_node->first_node( "vertices" ) )
			{
				std::vector<b2Vec2> verts;

				for (	rapidxml::xml_node<>* vert = vertices->first_node( "vertex" );
						vert != nullptr;
						vert = vert->next_sibling( vert->name( ) ) )
				{
					verts.push_back( g_inv_scale_b2_position * from_string<b2Vec2>( vert->value( ) ) );
				}

				if ( verts.size( ) )
				{
					b2PolygonShape polygon;
					polygon.Set( &verts.front( ), verts.size( ) );

					definition.shape = &polygon;

					m_body->CreateFixture( &definition );
				}
			}
		}
		else if ( type == "circle" )
		{
			b2CircleShape circle;
			circle.m_p = g_inv_scale_b2_position * read_from_node<b2Vec2>( shape_node->first_node( "position_offset" ), circle.m_p );
			circle.m_radius = g_inv_scale_b2_position * read_from_node<float32>( shape_node->first_node( "radius" ), circle.m_radius );

			definition.shape = &circle;
			m_body->CreateFixture( &definition );
		}
	}
}

void object::load_animation( rapidxml::xml_node<> * body_node )
{
	if ( rapidxml::xml_node<> * animation_node = body_node->first_node( "animation" ) )
	{
		try
		{
			m_animation = drawable_ptr( new animation( animation_node->value( ) ) );
		}
		catch ( std::runtime_error const & e )
		{
			OutputDebugStringA( e.what( ) );
		}
	}
}

void object::assign_user_data( )
{
	m_user_data.reset( new fire_event_user_data( m_body ) );
	m_body->SetUserData( static_cast<base_user_data *>( m_user_data.get( ) ) );
}
